/***************************************************************
 * Name:      QtHelper
 * Purpose:   Code::Blocks plugin
 * Author:    Sviridov Michael Alexandrovich (2mihail@mail.ru)
 * Created:   2008-09-20
 * Copyright: Sviridov Michael Alexandrovich
 * License:   GPL
 **************************************************************/

#include <wx/tokenzr.h>
#include <sdk.h>
#include <iostream>
#include "QtPrjDlg.h"
// #include "TiXmlFuncs.h"
#include <editpathdlg.h>
#include <filefilters.h>
//-------------------------------------------------
// #define brk(msg) cbMessageBox(_T(msg))
// TODO выбор в списке как-то по-другому обрабатывается

// TODO нужно ли загружать данные до включения плагина или только при включении выполнять считывание

// TODO сохранение данных можно делать по переключению на другой таргет или нет (скорее второе - т.к. при нажатии на ОК изменения таргета не происходит, а сохранять надо)
//-----------------------------------------------------------
// To save pointer in tree item data section
struct ScopeTreeData : public wxTreeItemData
{
	ConfigData *data;

	ScopeTreeData(ConfigData *dt = 0) : data(dt) {}
};
//-----------------------------------------------------------


BEGIN_EVENT_TABLE(QtPrjDlg, cbConfigurationPanel)
	EVT_CHECKBOX(XRCID("ID_USE_QT"), QtPrjDlg::on_use_qt)

	EVT_TREE_SEL_CHANGING(XRCID("ID_TARGETS_TREE"), QtPrjDlg::on_target_changing)
	EVT_TREE_SEL_CHANGED(XRCID("ID_TARGETS_TREE"), QtPrjDlg::on_target_changed)
	EVT_NOTEBOOK_PAGE_CHANGED(XRCID("ID_QT_PRJ_SETTINGS"), QtPrjDlg::on_page_changed)

	EVT_CHOICE(XRCID("ID_OUTPUT_TYPE"), QtPrjDlg::on_select_output_type)

	EVT_BUTTON(XRCID("ID_BROWSE_OUTPUT_FILENAME"), QtPrjDlg::on_browse_output_filename_click)
	EVT_TEXT(XRCID("ID_OUTPUT_FILENAME"), QtPrjDlg::on_output_filename_changed)

	EVT_BUTTON(XRCID("ID_BROWSE_EXE_WORK_DIR"), QtPrjDlg::on_browse_exe_work_dir_click)
	EVT_TEXT(XRCID("ID_EXE_WORK_DIR"), QtPrjDlg::on_exe_work_dir_changed)

	EVT_BUTTON(XRCID("ID_BROWSE_OBJECTS_DIR"), QtPrjDlg::on_browse_objects_dir_click)
	EVT_TEXT(XRCID("ID_OBJECTS_DIR"), QtPrjDlg::on_objects_dir_changed)

	EVT_LISTBOX(XRCID("ID_COMPILER_FLAGS_LIST"),QtPrjDlg::on_select_compiler_opt)
	EVT_BUTTON(XRCID("ID_ADD_COMPILER_FLAG"), QtPrjDlg::on_add_compiler_opt_click)
	EVT_BUTTON(XRCID("ID_DELETE_COMPILER_FLAG"), QtPrjDlg::on_delete_compiler_opt_click)
	EVT_BUTTON(XRCID("ID_CLEAR_COMPILER_FLAGS"), QtPrjDlg::on_clear_compiler_opts_click)

	EVT_LISTBOX(XRCID("ID_LINKER_FLAGS_LIST"),QtPrjDlg::on_select_linker_opt)
	EVT_BUTTON(XRCID("ID_ADD_LINKER_FLAG"), QtPrjDlg::on_add_linker_opt_click)
	EVT_BUTTON(XRCID("ID_DELETE_LINKER_FLAG"), QtPrjDlg::on_delete_linker_opt_click)
	EVT_BUTTON(XRCID("ID_CLEAR_LINKER_FLAGS"), QtPrjDlg::on_clear_linker_opts_click)

	EVT_LISTBOX(XRCID("ID_INCLUDE_PATHS_LIST"),QtPrjDlg::on_select_include_path)
	EVT_LISTBOX_DCLICK(XRCID("ID_INCLUDE_PATHS_LIST"), QtPrjDlg::on_edit_include_path_click)
	EVT_BUTTON(XRCID("ID_ADD_INCLUDE_PATH"), QtPrjDlg::on_add_include_path_click)
	EVT_BUTTON(XRCID("ID_EDIT_INCLUDE_PATH"), QtPrjDlg::on_edit_include_path_click)
	EVT_BUTTON(XRCID("ID_DELETE_INCLUDE_PATH"), QtPrjDlg::on_delete_include_path_click)
	EVT_BUTTON(XRCID("ID_CLEAR_INCLUDE_PATHS"), QtPrjDlg::on_clear_include_paths_click)
	EVT_SPIN_UP(XRCID("ID_MOVE_INCLUDE_PATH"), QtPrjDlg::on_move_up_include_path)
	EVT_SPIN_DOWN(XRCID("ID_MOVE_INCLUDE_PATH"), QtPrjDlg::on_move_down_include_path)

	EVT_LISTBOX(XRCID("ID_LIB_PATHS_LIST"),QtPrjDlg::on_select_lib_path)
	EVT_LISTBOX_DCLICK(XRCID("ID_LIB_PATHS_LIST"), QtPrjDlg::on_edit_lib_path_click)
	EVT_BUTTON(XRCID("ID_ADD_LIB_PATH"), QtPrjDlg::on_add_lib_path_click)
	EVT_BUTTON(XRCID("ID_EDIT_LIB_PATH"), QtPrjDlg::on_edit_lib_path_click)
	EVT_BUTTON(XRCID("ID_DELETE_LIB_PATH"), QtPrjDlg::on_delete_lib_path_click)
	EVT_BUTTON(XRCID("ID_CLEAR_LIB_PATHS"), QtPrjDlg::on_clear_lib_path_click)
	EVT_SPIN_UP(XRCID("ID_MOVE_LIB_PATH"), QtPrjDlg::on_move_up_lib_path)
	EVT_SPIN_DOWN(XRCID("ID_MOVE_LIB_PATH"), QtPrjDlg::on_move_down_lib_path)

	EVT_LISTBOX(XRCID("ID_LIBS_LIST"),QtPrjDlg::on_select_lib)
	EVT_LISTBOX_DCLICK(XRCID("ID_LIBS_LIST"), QtPrjDlg::on_edit_lib_click)
	EVT_BUTTON(XRCID("ID_ADD_LIB"), QtPrjDlg::on_add_lib_click)
	EVT_BUTTON(XRCID("ID_EDIT_LIB"), QtPrjDlg::on_edit_lib_click)
	EVT_BUTTON(XRCID("ID_DELETE_LIB"), QtPrjDlg::on_delete_lib_click)
	EVT_BUTTON(XRCID("ID_CLEAR_LIBS"), QtPrjDlg::on_clear_lib_click)
	EVT_SPIN_UP(XRCID("ID_MOVE_LIB"), QtPrjDlg::on_move_up_lib)
	EVT_SPIN_DOWN(XRCID("ID_MOVE_LIB"), QtPrjDlg::on_move_down_lib)

	EVT_TEXT(XRCID("ID_CUSTOM_EDIT"), QtPrjDlg::on_custom_tags_changed)
END_EVENT_TABLE()
//-------------------------------------------------
QtPrjDlg::QtPrjDlg(wxWindow* parent, cbProject* prj) : project(prj)
{
	modified = false;
	loaded = false;
	loading = true;

	wxXmlResource::Get()->LoadPanel(this, parent, _T("QtPrjDlg"));

	//extracting param that allows use this plugin
	TiXmlNode *prj_node = project->GetExtensionsNode();
	TiXmlElement *qt_node = prj_node->FirstChildElement("qt_helper");
	bool use_qt = false;
	TiXmlElement *prm;

	if(qt_node)
	{
		TiXmlElement *elem = qt_node->FirstChildElement("enabled");
		if(elem && cbC2U(elem->Attribute("value")) == cbC2U("true"))
			use_qt = true;
	}

	use_qt_check()->SetValue(use_qt);

	wxCommandEvent event;
	on_use_qt(event);
}
//-------------------------------------------------
QtPrjDlg::~QtPrjDlg()
{}
//-------------------------------------------------
//{ GETTERS FOR WIDGETS POINTERS
// getting pointer to targets tree widget
wxTreeCtrl* QtPrjDlg::targets_tree()
{
	return XRCCTRL(*this, "ID_TARGETS_TREE", wxTreeCtrl);
}
//-----------------------------------------------------------
// getting pointer to settings notebook widget
wxNotebook* QtPrjDlg::qt_prj_settings()
{
	return XRCCTRL(*this, "ID_QT_PRJ_SETTINGS", wxNotebook);
}
//-----------------------------------------------------------
// getting pointer to settings notebook pages
wxPanel* QtPrjDlg::build_options()
{
	return XRCCTRL(*this, "ID_BUILD_OPTIONS", wxPanel);
}
//-----------------------------------------------------------
wxPanel* QtPrjDlg::build_flags()
{
	return XRCCTRL(*this, "ID_BUILD_FLAGS", wxPanel);
}
//-----------------------------------------------------------
wxPanel* QtPrjDlg::search_paths()
{
	return XRCCTRL(*this, "ID_SEARCH_PATHS", wxPanel);
}
//-----------------------------------------------------------
wxPanel* QtPrjDlg::link_libs()
{
	return XRCCTRL(*this, "ID_LINK_LIBS", wxPanel);
}
//-----------------------------------------------------------
// getting pointers to include dirs widgets
wxListBox* QtPrjDlg::inc_dir_lst()
{
	return XRCCTRL(*this, "ID_INCLUDE_PATHS_LIST", wxListBox);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::add_inc_dir_btn()
{
	return XRCCTRL(*this, "ID_ADD_INCLUDE_PATH", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::edit_inc_dir_btn()
{
	return XRCCTRL(*this, "ID_EDIT_INCLUDE_PATH", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::delete_inc_dir_btn()
{
	return XRCCTRL(*this, "ID_DELETE_INCLUDE_PATH", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::clear_inc_dirs_btn()
{
	return XRCCTRL(*this, "ID_CLEAR_INCLUDE_PATHS", wxButton);
}
//-----------------------------------------------------------
wxSpinButton* QtPrjDlg::move_inc_dir_btn()
{
	return XRCCTRL(*this, "ID_MOVE_INCLUDE_PATH", wxSpinButton);
}
//-----------------------------------------------------------
// getting pointers to lib dirs widgets
wxListBox* QtPrjDlg::lib_dir_lst()
{
	return XRCCTRL(*this, "ID_LIB_PATHS_LIST", wxListBox);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::add_lib_dir_btn()
{
	return XRCCTRL(*this, "ID_ADD_LIB_PATH", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::edit_lib_dir_btn()
{
	return XRCCTRL(*this, "ID_EDIT_LIB_PATH", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::delete_lib_dir_btn()
{
	return XRCCTRL(*this, "ID_DELETE_LIB_PATH", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::clear_lib_dirs_btn()
{
	return XRCCTRL(*this, "ID_CLEAR_LIB_PATHS", wxButton);
}
//-----------------------------------------------------------
wxSpinButton* QtPrjDlg::move_lib_dir_btn()
{
	return XRCCTRL(*this, "ID_MOVE_LIB_PATH", wxSpinButton);
}
//-----------------------------------------------------------
// getting pointers to libs widgets
wxListBox* QtPrjDlg::libs_lst()
{
	return XRCCTRL(*this, "ID_LIBS_LIST", wxListBox);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::add_lib_btn()
{
	return XRCCTRL(*this, "ID_ADD_LIB", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::edit_lib_btn()
{
	return XRCCTRL(*this, "ID_EDIT_LIB", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::delete_lib_btn()
{
	return XRCCTRL(*this, "ID_DELETE_LIB", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::clear_libs_btn()
{
	return XRCCTRL(*this, "ID_CLEAR_LIBS", wxButton);
}
//-----------------------------------------------------------
wxSpinButton* QtPrjDlg::move_lib_btn()
{
	return XRCCTRL(*this, "ID_MOVE_LIB", wxSpinButton);
}
//-----------------------------------------------------------
// getting pointer to use_qt checkbox
wxCheckBox* QtPrjDlg::use_qt_check()
{
	return XRCCTRL(*this, "ID_USE_QT", wxCheckBox);
}
//-----------------------------------------------------------
// getting pointer to build options widgets
wxChoice* QtPrjDlg::output_type_edit()
{
	return XRCCTRL(*this, "ID_OUTPUT_TYPE", wxChoice);
}
//-----------------------------------------------------------
wxTextCtrl* QtPrjDlg::output_filename_edit()
{
	return XRCCTRL(*this, "ID_OUTPUT_FILENAME", wxTextCtrl);
}
//-----------------------------------------------------------
wxTextCtrl* QtPrjDlg::exe_work_dir_edit()
{
	return XRCCTRL(*this, "ID_EXE_WORK_DIR", wxTextCtrl);
}
//-----------------------------------------------------------
wxTextCtrl* QtPrjDlg::obj_dir_edit()
{
	return XRCCTRL(*this, "ID_OBJECTS_DIR", wxTextCtrl);
}
//-----------------------------------------------------------
// getting pointer to compiler flags widgets
wxListBox* QtPrjDlg::compiler_opts_lst()
{
	return XRCCTRL(*this, "ID_COMPILER_FLAGS_LIST", wxListBox);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::add_compiler_opt_btn()
{
	return XRCCTRL(*this, "ID_ADD_COMPILER_FLAG", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::delete_compiler_opt_btn()
{
	return XRCCTRL(*this, "ID_DELETE_COMPILER_FLAG", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::clear_compiler_opts_btn()
{
	return XRCCTRL(*this, "ID_CLEAR_COMPILER_FLAGS", wxButton);
}
//-----------------------------------------------------------
// getting pointer to linker flags widgets
wxListBox* QtPrjDlg::linker_opts_lst()
{
	return XRCCTRL(*this, "ID_LINKER_FLAGS_LIST", wxListBox);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::add_linker_opt_btn()
{
	return XRCCTRL(*this, "ID_ADD_LINKER_FLAG", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::delete_linker_opt_btn()
{
	return XRCCTRL(*this, "ID_DELETE_LINKER_FLAG", wxButton);
}
//-----------------------------------------------------------
wxButton* QtPrjDlg::clear_linker_opts_btn()
{
	return XRCCTRL(*this, "ID_CLEAR_LINKER_FLAGS", wxButton);
}
//-----------------------------------------------------------
wxTextCtrl* QtPrjDlg::custom_tags_edit()
{
	return XRCCTRL(*this, "ID_CUSTOM_EDIT", wxTextCtrl);
}
//-----------------------------------------------------------
//}
//{ HANDLERS
void QtPrjDlg::on_use_qt(wxCommandEvent&)
{
	bool enabled = use_qt_check()->GetValue();
	targets_tree()->Enable(enabled);
	qt_prj_settings()->Enable(enabled);

	if(!loading)
	{
		// auto enable custom makefile usage
		//project->SetMakefileCustom(enabled);
		modified = true;
	}

	if(enabled)
		load();

	loading = false;
}
//-------------------------------------------------
void QtPrjDlg::on_target_changing(wxTreeEvent&)
{

}
//-----------------------------------------------------------
void QtPrjDlg::on_target_changed(wxTreeEvent &event)
{
	if(loading)
		return;

	wxTreeItemId root_id = targets_tree()->GetRootItem();
	wxTreeItemId cur_item_id = event.GetItem();
	wxTreeItemId prev_item_id = event.GetOldItem();

	// before this selection was another selection that must be saved
	if(prev_item_id.IsOk())
	{
		// if it was root -> saving project settings
		if(prev_item_id == root_id)
			save_project_data();
		else
			save_target_data(prev_item_id);
	}

	// if now selected root -> loading project's settings
	if(cur_item_id == root_id)
	{
		load_project_data();
		build_options()->Enable(false);
	}
	else
	{
		load_target_data(cur_item_id);
		build_options()->Enable(true);
	}
}
//-----------------------------------------------------------
void QtPrjDlg::on_page_changed(wxNotebookEvent&)
{
	/*int cur_page = qt_prj_settings()->GetSelection();

	long style = targets_tree()->GetWindowStyle();
	if(qt_prj_settings()->GetPage(cur_page) == build_options())
		targets_tree()->SetWindowStyle(style | wxTR_HIDE_ROOT);
	else
		targets_tree()->SetWindowStyle(style & (~wxTR_HIDE_ROOT));*/
}
//-----------------------------------------------------------
void QtPrjDlg::on_select_output_type(wxCommandEvent&)
{
	get_config().modified = true;
}
//-----------------------------------------------------------
void QtPrjDlg::on_browse_output_filename_click(wxCommandEvent&)
{
	wxString str = output_filename_edit()->GetValue();
	Manager::Get()->GetMacrosManager()->ReplaceEnvVars(str);

	wxFileName out_fn;
	out_fn.Assign(str);
	wxFileDialog dlg(this,
                    _("Select output filename"),
                    out_fn.GetPath(),
                    out_fn.GetFullName(),
                    FileFilters::GetFilterAll(),
                    wxFD_SAVE | wxFD_OVERWRITE_PROMPT);

    PlaceWindow(&dlg);
    if (dlg.ShowModal() != wxID_OK)
        return;

    out_fn.Assign(dlg.GetPath());
    out_fn.MakeRelativeTo(project->GetBasePath());
    output_filename_edit()->SetValue(out_fn.GetFullPath());
}
//-----------------------------------------------------------
void QtPrjDlg::on_output_filename_changed(wxCommandEvent&)
{
	if(loading)
		return;

	get_config().modified = true;
}
//-----------------------------------------------------------
void QtPrjDlg::on_browse_exe_work_dir_click(wxCommandEvent&)
{
	wxString dir = browse_dir(_T("Select working directory for executable"), exe_work_dir_edit()->GetValue());
	if(!dir.IsEmpty())
		exe_work_dir_edit()->SetValue(dir);
}
//-----------------------------------------------------------
void QtPrjDlg::on_exe_work_dir_changed(wxCommandEvent&)
{
	if(loading)
		return;

	get_config().modified = true;
}
//-----------------------------------------------------------
void QtPrjDlg::on_browse_objects_dir_click(wxCommandEvent&)
{
	wxString dir = browse_dir(_T("Select objects output directory"), obj_dir_edit()->GetValue());
	if(!dir.IsEmpty())
		obj_dir_edit()->SetValue(dir);
}
//-----------------------------------------------------------
void QtPrjDlg::on_objects_dir_changed(wxCommandEvent&)
{
	if(loading)
		return;

	get_config().modified = true;
}
//-----------------------------------------------------------
void QtPrjDlg::on_select_compiler_opt(wxCommandEvent&)
{
	update_compiler_opt_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_add_compiler_opt_click(wxCommandEvent&)
{
	wxTextEntryDialog dlg(this, _T("Add options"), _T("Enter compiler options"), _T(""), wxOK | wxCANCEL);

	PlaceWindow(&dlg);
    if (dlg.ShowModal() == wxID_OK)
    {
		wxArrayString opts = GetArrayFromString(dlg.GetValue(), _T(" "), true);
		for(int i=0; i<opts.Count(); ++i)
			compiler_opts_lst()->Append(opts[i]);

		if(opts.Count())
			get_config().modified = true;
    }
}
//-----------------------------------------------------------
void QtPrjDlg::on_delete_compiler_opt_click(wxCommandEvent&)
{
	delete_list_item(compiler_opts_lst());
	update_compiler_opt_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_clear_compiler_opts_click(wxCommandEvent&)
{
	clear_list(compiler_opts_lst());
	update_compiler_opt_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_select_linker_opt(wxCommandEvent&)
{
	update_linker_opt_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_add_linker_opt_click(wxCommandEvent&)
{
	wxTextEntryDialog dlg(this, _T("Add options"), _T("Enter linker options"), _T(""), wxOK | wxCANCEL);

	PlaceWindow(&dlg);
    if (dlg.ShowModal() == wxID_OK)
    {
		wxArrayString opts = GetArrayFromString(dlg.GetValue(), _T(" "), true);
		for(int i=0; i<opts.Count(); ++i)
			linker_opts_lst()->Append(opts[i]);

		if(opts.Count())
			get_config().modified = true;
    }
}
//-----------------------------------------------------------
void QtPrjDlg::on_delete_linker_opt_click(wxCommandEvent&)
{
	delete_list_item(linker_opts_lst());
	update_linker_opt_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_clear_linker_opts_click(wxCommandEvent&)
{
	clear_list(linker_opts_lst());
	update_linker_opt_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_select_include_path(wxCommandEvent&)
{
	update_include_dir_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_add_include_path_click(wxCommandEvent&)
{
	add_dir(inc_dir_lst());
	update_include_dir_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_edit_include_path_click(wxCommandEvent&)
{
	edit_dir(inc_dir_lst());
}
//-----------------------------------------------------------
void QtPrjDlg::on_delete_include_path_click(wxCommandEvent&)
{
	delete_list_item(inc_dir_lst());
	update_include_dir_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_clear_include_paths_click(wxCommandEvent&)
{
	clear_list(inc_dir_lst());
	update_include_dir_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_move_up_include_path(wxSpinEvent&)
{
	move_up_list_item(inc_dir_lst());
}
//-----------------------------------------------------------
void QtPrjDlg::on_move_down_include_path(wxSpinEvent&)
{
	move_down_list_item(inc_dir_lst());
}
//-----------------------------------------------------------
void QtPrjDlg::on_select_lib_path(wxCommandEvent&)
{
	update_lib_dir_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_add_lib_path_click(wxCommandEvent&)
{
	add_dir(lib_dir_lst());
	update_lib_dir_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_edit_lib_path_click(wxCommandEvent&)
{
	edit_dir(lib_dir_lst());
}
//-----------------------------------------------------------
void QtPrjDlg::on_delete_lib_path_click(wxCommandEvent&)
{
	delete_list_item(lib_dir_lst());
	update_lib_dir_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_clear_lib_path_click(wxCommandEvent&)
{
	clear_list(lib_dir_lst());
	update_lib_dir_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_move_up_lib_path(wxSpinEvent&)
{
	move_up_list_item(lib_dir_lst());
}
//-----------------------------------------------------------
void QtPrjDlg::on_move_down_lib_path(wxSpinEvent&)
{
	move_down_list_item(lib_dir_lst());
}
//-----------------------------------------------------------
void QtPrjDlg::on_select_lib(wxCommandEvent&)
{
	update_lib_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_add_lib_click(wxCommandEvent&)
{
	EditPathDlg dlg(this,
            _T(""),
            project? project->GetBasePath() : _T(""),
            _("Add library"),
            _("Choose library to link"),
            false,
            true,
            _("Library files (*.a, *.so, *.lib, *.dylib, *.bundle)|*.a;*.so;*.lib;*.dylib;*.bundle|All files (*)|*"));

    PlaceWindow(&dlg);
    if (dlg.ShowModal() == wxID_OK)
    {
        wxArrayString paths = GetArrayFromString(dlg.GetPath());
        for (unsigned int i=0; i<paths.GetCount(); ++i)
        {
            libs_lst()->Append(paths[i]);
        }

        if(paths.Count())
			get_config().modified = true;
    }
}
//-----------------------------------------------------------
void QtPrjDlg::on_edit_lib_click(wxCommandEvent&)
{
    EditPathDlg dlg(this,
            libs_lst()->GetStringSelection(),
			project? project->GetBasePath() : _T(""),
			_("Edit library"),
            _("Choose library to link"),
            false,
            false,
            _("Library files (*.a, *.so, *.lib, *.dylib, *.bundle)|*.a;*.so;*.lib;*.dylib;*.bundle|All files (*)|*"));

    PlaceWindow(&dlg);
	if (dlg.ShowModal() == wxID_OK)
    {
        libs_lst()->SetString(libs_lst()->GetSelection(), dlg.GetPath());
        get_config().modified = true;
    }
}
//-----------------------------------------------------------
void QtPrjDlg::on_delete_lib_click(wxCommandEvent&)
{
	delete_list_item(libs_lst());
	update_lib_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_clear_lib_click(wxCommandEvent&)
{
	clear_list(libs_lst());
	update_lib_btns();
}
//-----------------------------------------------------------
void QtPrjDlg::on_move_up_lib(wxSpinEvent&)
{
	move_up_list_item(libs_lst());
}
//-----------------------------------------------------------
void QtPrjDlg::on_move_down_lib(wxSpinEvent&)
{
	move_down_list_item(libs_lst());
}
//-----------------------------------------------------------
void QtPrjDlg::on_custom_tags_changed(wxCommandEvent&)
{
	if(loading)
		return;

	get_config().modified = true;
}
//-----------------------------------------------------------
//}
void QtPrjDlg::load()
{
	if(loaded)
		return;

	loading = true;
	loaded = true;

	wxTreeItemId root_id = targets_tree()->AddRoot(project->GetTitle(), -1, -1, new ScopeTreeData(&project_cfg));

	// extracting project config to preallocated container
	project_cfg.compiler_opts = project->GetCompilerOptions();
	project_cfg.linker_opts = project->GetLinkerOptions();
	project_cfg.inc_dirs = project->GetIncludeDirs();
	project_cfg.lib_dirs = project->GetLibDirs();
	project_cfg.libs = project->GetLinkLibs();

	TiXmlNode *prj_node = project->GetExtensionsNode();
	TiXmlElement *elem = prj_node->FirstChildElement("qt_helper");
	if(elem)
	{
		elem = elem->FirstChildElement("custom_tags");
		if(elem)
		{
			const char *text = elem->Attribute("value");
			if(text)
				project_cfg.custom_tags = cbC2U(text);
		}
	}

	project_cfg.modified = false;

	// allocate memory for targets config
	targets_cfg.resize(project->GetBuildTargetsCount());

	for(int i=0; i<targets_cfg.size(); ++i)
	{
		// adding item in the targets tree
		ProjectBuildTarget *target = project->GetBuildTarget(i);
		wxString target_name = target->GetTitle();
		targets_tree()->AppendItem(root_id, target_name, -1, -1, new ScopeTreeData(&targets_cfg[i]));

		// extracting targets config to preallocated container
		targets_cfg[i].output_type = target->GetTargetType();
		targets_cfg[i].output_filename = target->GetOutputFilename();
		targets_cfg[i].exe_work_dir = target->GetWorkingDir();
		targets_cfg[i].objects_dir = target->GetObjectOutput();

		targets_cfg[i].compiler_opts = target->GetCompilerOptions();
		targets_cfg[i].linker_opts = target->GetLinkerOptions();
		targets_cfg[i].inc_dirs = target->GetIncludeDirs();
		targets_cfg[i].lib_dirs = target->GetLibDirs();
		targets_cfg[i].libs = target->GetLinkLibs();

		elem = prj_node->FirstChildElement("qt_helper");
		if(elem)
		{
			elem = elem->FirstChildElement("targets");
			if(elem)
			{
				elem = elem->FirstChildElement(cbU2C(target->GetTitle()));
				if(elem)
				{
					elem = elem->FirstChildElement("custom_tags");
					if(elem)
					{
						const char *text = elem->Attribute("value");
						if(text)
							targets_cfg[i].custom_tags = cbC2U(text);
					}
				}
			}
		}

		targets_cfg[i].modified = false;
	}

	targets_tree()->ExpandAll();
	loading = false;

	targets_tree()->SelectItem(root_id);
}
//-----------------------------------------------------------
void QtPrjDlg::load_project_data()
{
	loading = true;

	// filling compiler and linker options
	compiler_opts_lst()->Set(project_cfg.compiler_opts);
	update_compiler_opt_btns();

	linker_opts_lst()->Set(project_cfg.linker_opts);
	update_linker_opt_btns();

	// filling include paths list
	inc_dir_lst()->Set(project_cfg.inc_dirs);
	update_include_dir_btns();

	// filling libs paths list
	lib_dir_lst()->Set(project_cfg.lib_dirs);
	update_lib_dir_btns();

	// filling libs list
	libs_lst()->Set(project_cfg.libs);
	update_lib_btns();

	// filling custom tags edit
	custom_tags_edit()->SetValue(project_cfg.custom_tags);

	loading = false;
}
//-----------------------------------------------------------
void QtPrjDlg::load_target_data(const wxTreeItemId &id)
{
	loading = true;

	ConfigData &data = get_config(id);

	// update other fields of panel
	output_type_edit()->SetSelection(data.output_type);
	output_filename_edit()->SetValue(data.output_filename);
	exe_work_dir_edit()->SetValue(data.exe_work_dir);
	obj_dir_edit()->SetValue(data.objects_dir);

	// filling compiler and linker options
	compiler_opts_lst()->Set(data.compiler_opts);
	update_compiler_opt_btns();

	linker_opts_lst()->Set(data.linker_opts);
	update_linker_opt_btns();

	// filling include paths list
	inc_dir_lst()->Set(data.inc_dirs);
	update_include_dir_btns();

	// filling libs paths list
	lib_dir_lst()->Set(data.lib_dirs);
	update_lib_dir_btns();

	// filling libs list
	libs_lst()->Set(data.libs);
	update_lib_btns();

	// filling custom tags edit
	custom_tags_edit()->SetValue(data.custom_tags);

	loading = false;
}
//-----------------------------------------------------------
void QtPrjDlg::save_project_data()
{
	if(!project_cfg.modified)
		return;

	project_cfg.compiler_opts = compiler_opts_lst()->GetStrings();
	project_cfg.linker_opts = linker_opts_lst()->GetStrings();
	project_cfg.inc_dirs = inc_dir_lst()->GetStrings();
	project_cfg.lib_dirs = lib_dir_lst()->GetStrings();
	project_cfg.libs = libs_lst()->GetStrings();
	project_cfg.custom_tags = custom_tags_edit()->GetValue();
}
//-----------------------------------------------------------
void QtPrjDlg::save_target_data(const wxTreeItemId &id)
{
	ConfigData &data = get_config(id);
	if(!data.modified)
		return;

	data.output_type = output_type_edit()->GetSelection();
	data.output_filename = output_filename_edit()->GetValue();
	data.exe_work_dir = exe_work_dir_edit()->GetValue();
	data.objects_dir = obj_dir_edit()->GetValue();

	data.compiler_opts = compiler_opts_lst()->GetStrings();
	data.linker_opts = linker_opts_lst()->GetStrings();
	data.inc_dirs = inc_dir_lst()->GetStrings();
	data.lib_dirs = lib_dir_lst()->GetStrings();
	data.libs = libs_lst()->GetStrings();
	data.custom_tags = custom_tags_edit()->GetValue();
}
//-----------------------------------------------------------
void QtPrjDlg::save()
{
	bool use_qt = use_qt_check()->GetValue();

	// saving 'use QtHelper'
	TiXmlNode *prj_node = project->GetExtensionsNode();
	TiXmlElement *qt_node = prj_node->FirstChildElement("qt_helper");

	if(modified)
	{
		modified = false;
		if(!qt_node)
		{
			if(!use_qt)
				return;

			qt_node = prj_node->LinkEndChild(new TiXmlElement("qt_helper"))->ToElement();
		}

		getXmlElement(qt_node, "enabled")->SetAttribute("value", use_qt? "true" : "false");
	}

	if(!use_qt)
		return;

	wxTreeItemId cur_item_id = targets_tree()->GetSelection();
	wxTreeItemId root_id = targets_tree()->GetRootItem();

	if(project_cfg.modified)
	{
		if(cur_item_id.IsOk() && cur_item_id == root_id)
			save_project_data();

		project_cfg.modified = false;
		// saving project config from preallocated container
		project->SetCompilerOptions(project_cfg.compiler_opts);
		project->SetLinkerOptions(project_cfg.linker_opts);
		project->SetIncludeDirs(project_cfg.inc_dirs);
		project->SetLibDirs(project_cfg.lib_dirs);
		project->SetLinkLibs(project_cfg.libs);

		getXmlElement(qt_node, "custom_tags")->SetAttribute("value", cbU2C(project_cfg.custom_tags));
	}

	// need to save this data
	save_target_data(targets_tree()->GetSelection());

	for(int i=0; i<targets_cfg.size(); ++i)
	{
		if(targets_cfg[i].modified)
		{
			if(cur_item_id.IsOk() && cur_item_id != root_id)
				save_target_data(cur_item_id);

			targets_cfg[i].modified = false;

			ProjectBuildTarget *target = project->GetBuildTarget(i);

			// saving targets config from preallocated container
			target->SetTargetType((TargetType)targets_cfg[i].output_type);
			target->SetTargetFilenameGenerationPolicy(tgfpNone, tgfpNone); // disable auto prefix and auto suffix for filename
			target->SetOutputFilename(targets_cfg[i].output_filename);
			target->SetWorkingDir(targets_cfg[i].exe_work_dir);
			target->SetObjectOutput(targets_cfg[i].objects_dir);

			target->SetCompilerOptions(targets_cfg[i].compiler_opts);
			target->SetLinkerOptions(targets_cfg[i].linker_opts);
			target->SetIncludeDirs(targets_cfg[i].inc_dirs);
			target->SetLibDirs(targets_cfg[i].lib_dirs);
			target->SetLinkLibs(targets_cfg[i].libs);

			TiXmlElement *target_custom_tags = getXmlElement(getXmlElement(getXmlElement(qt_node, "targets"), cbU2C(target->GetTitle())),  "custom_tags");
			target_custom_tags->SetAttribute("value", cbU2C(targets_cfg[i].custom_tags));
		}
	}
}
//-------------------------------------------------
// some handlers for adding/editing/removing/clearing of include/libraries/resources directories
void QtPrjDlg::add_dir(wxListBox *lst)
{
	if (!lst)
        return;

    EditPathDlg dlg(this,
			project->GetBasePath(),
			project->GetBasePath(),
			_("Add directory"));

    PlaceWindow(&dlg);
    if (dlg.ShowModal() == wxID_OK)
    {
		lst->Append(dlg.GetPath());
		get_config().modified = true;
    }
}
//-----------------------------------------------------------
void QtPrjDlg::edit_dir(wxListBox *lst)
{
    if (!lst || lst->GetSelection() < 0)
        return;

    EditPathDlg dlg(this,
            lst->GetStringSelection(),
            project? project->GetBasePath() : _T(""),
            _("Edit directory"));

    PlaceWindow(&dlg);
    if (dlg.ShowModal() == wxID_OK)
    {
        wxString path = dlg.GetPath();
        lst->SetString(lst->GetSelection(), path);
        get_config().modified = true;
    }
}
//-----------------------------------------------------------
void QtPrjDlg::delete_list_item(wxListBox *lst)
{
    if (!lst || lst->GetSelection() < 0)
        return;

	if (cbMessageBox(_("Remove '") + lst->GetStringSelection() + _("' from the list?"),
                    _("Confirmation"),
                    wxOK | wxCANCEL | wxICON_QUESTION) == wxID_OK)
    {
        lst->Delete(lst->GetSelection());
        get_config().modified = true;
    }
}
//-----------------------------------------------------------
void QtPrjDlg::clear_list(wxListBox *lst)
{
    if (!lst || !lst->GetCount())
        return;

	if (cbMessageBox(_("Remove all entries from the list?"),
                    _("Confirmation"),
                    wxOK | wxCANCEL | wxICON_QUESTION) == wxID_OK)
    {
        lst->Clear();
        get_config().modified = true;
    }
}
//-----------------------------------------------------------
void QtPrjDlg::move_up_list_item(wxListBox *lst)
{
	if (!lst)
        return;

	int cur = lst->GetSelection();
	if(cur <= 0)
		return;

	wxString tmp = lst->GetString(cur);
	lst->SetString(cur, lst->GetString(cur - 1));
	lst->SetString(cur - 1, tmp);
	lst->SetSelection(cur - 1);
	get_config().modified = true;
}
//-----------------------------------------------------------
void QtPrjDlg::move_down_list_item(wxListBox *lst)
{
	if (!lst || lst->GetSelection() < 0)
        return;

	int cur = lst->GetSelection();
	if(cur >= lst->GetCount() - 1)
		return;

	wxString tmp = lst->GetString(cur);
	lst->SetString(cur, lst->GetString(cur + 1));
	lst->SetString(cur + 1, tmp);
	lst->SetSelection(cur + 1);
	get_config().modified = true;
}
//-----------------------------------------------------------
void QtPrjDlg::update_compiler_opt_btns()
{
	bool enabled = (compiler_opts_lst()->GetSelection() >= 0);
	delete_compiler_opt_btn()->Enable(enabled);
}
//-----------------------------------------------------------
void QtPrjDlg::update_linker_opt_btns()
{
	bool enabled = (linker_opts_lst()->GetSelection() >= 0);
	delete_linker_opt_btn()->Enable(enabled);
}
//-----------------------------------------------------------
void QtPrjDlg::update_include_dir_btns()
{
	int index = inc_dir_lst()->GetSelection();
	bool enabled = (index >= 0);
	edit_inc_dir_btn()->Enable(enabled);
	delete_inc_dir_btn()->Enable(enabled);
	move_inc_dir_btn()->SetRange(0, inc_dir_lst()->GetCount());
	move_inc_dir_btn()->Enable(enabled);
	move_inc_dir_btn()->SetValue(index);
}
//-----------------------------------------------------------
void QtPrjDlg::update_lib_dir_btns()
{
	int index = lib_dir_lst()->GetSelection();
	bool enabled = (index >= 0);
	edit_lib_dir_btn()->Enable(enabled);
	delete_lib_dir_btn()->Enable(enabled);
	move_lib_dir_btn()->SetRange(0, lib_dir_lst()->GetCount());
	move_lib_dir_btn()->Enable(enabled);
	move_lib_dir_btn()->SetValue(index);
}
//-----------------------------------------------------------
void QtPrjDlg::update_lib_btns()
{
	int index = libs_lst()->GetSelection();
	bool enabled = (index >= 0);
	edit_lib_btn()->Enable(enabled);
	delete_lib_btn()->Enable(enabled);
	move_lib_btn()->SetRange(0, libs_lst()->GetCount());
	move_lib_btn()->Enable(enabled);
	move_lib_btn()->SetValue(index);
}
//-----------------------------------------------------------
ConfigData& QtPrjDlg::get_config(const wxTreeItemId &id)
{
	ScopeTreeData *data = (ScopeTreeData*)targets_tree()->GetItemData(id.IsOk()? id : targets_tree()->GetSelection());
	return *data->data;
}
//-----------------------------------------------------------
wxString QtPrjDlg::browse_dir(const wxString &text, const wxString &dir)
{
	wxString str = dir;
	Manager::Get()->GetMacrosManager()->ReplaceEnvVars(str);
	wxString base_path = project? project->GetBasePath() : _T("");
	wxFileName fn(str);
	fn.MakeAbsolute(base_path);
	str = fn.GetFullPath();
	return ChooseDirectory(this, text, str, base_path, true, true);
}
//-----------------------------------------------------------
TiXmlElement* QtPrjDlg::getXmlElement(TiXmlNode *parent, const char *name) const
{
	TiXmlElement *elem = parent->FirstChildElement(name);
	if(!elem)
	{
		elem = new TiXmlElement(name);
		parent->LinkEndChild(elem);
	}

	return elem;
}
//-----------------------------------------------------------
